#-- coding: utf-8 --

#@File : oss_util.py.py
#@Software : PyCharm
#@Author : Silva
#@Email : for_billy@163.com
#@Time : 2023/10/6 下午3:28


import os
import time
import shutil
import oss2
from urllib import parse
from oss2 import Bucket

import requests
import json



class OssClient(object):
    def __init__(self, bucket=None, access_id=None, access_key=None,
                 end_point=None, end_internal_point=None, bizType='default'):
        self.BUCKET = bucket
        self.ACCESS_ID = access_id
        self.ACCESS_KEY = access_key
        self.END_POINT = end_point
        self.END_INTERNAL_POINT = end_internal_point

        self.oss_config = None
        self.oss_expiration = 0
        self.bizType = bizType
        self.reload_oss_config()

    def reload_oss_config(self):
        if not self.oss_config or int(time.time()) > self.oss_expiration:
            self.oss_config = self.get_oss_config_dynamic(self.bizType)
            self.oss_expiration = self.oss_config['oss.expiration']
            self.BUCKET = self.oss_config['oss.bucket']
            self.ACCESS_ID = self.oss_config['oss.access_id']
            self.ACCESS_KEY = self.oss_config['oss.access_key']
            self.ACCESS_TOKEN = self.oss_config['oss.access_token']
            self.END_POINT = self.oss_config['oss.end_point']
            self.END_INTERNAL_POINT = self.oss_config['oss.end_internal_point']
            self.DIR = self.oss_config['oss.dir']


    def get_oss_config_dynamic(self, bizType='default'):
        url = "http://120.79.55.91:80/api/oss/create/sts/token/out"
        payload = json.dumps({
            "bizType": "{}".format(bizType)
        })
        headers = {
            'Authorization': '4e866ec420b78f3b8b6e65491cdbc149',
            'Content-Type': 'application/json'
        }
        response = requests.request("POST", url, headers=headers, data=payload)
        data = response.json()
        accessKeyId = data['data']['credentials']['accessKeyId']
        accessKeySecret = data['data']['credentials']['accessKeySecret']
        securityToken = data['data']['credentials']['securityToken']
        expiration = data['data']['credentials']['expiration']

        dir = data['data']['dir']
        bucket = data['data']['bucket']
        region = data['data']['region']

        return {
            'oss.access_id': accessKeyId,
            'oss.access_key': accessKeySecret,
            'oss.access_token': securityToken,
            'oss.expiration': expiration,
            'oss.dir': dir,
            'oss.bucket': bucket,
            'oss.end_point': f'{region}.aliyuncs.com',
            'oss.end_internal_point': f'{region}.aliyuncs.com'

        }

    def get_oss_bucket(self):
        self.reload_oss_config()
        # auth = oss2.Auth(self.ACCESS_ID, self.ACCESS_KEY)
        auth = oss2.StsAuth(self.ACCESS_ID, self.ACCESS_KEY, self.ACCESS_TOKEN)
        bck = oss2.Bucket(auth, self.END_INTERNAL_POINT, self.BUCKET)
        return bck

    def upload_file(self, file_buffer, key, private=False):
        """
        上传文件
        :param file_buffer: bytes，str或file-like object
        :param key:
        :param private: 设置为私有(如果bucket拥有公共读权限，上传的文件会不能获取sign_url)
        :return err_code:
            0: 操作成功
            1: 操作失败
        """
        bucket = self.get_oss_bucket()
        result = bucket.put_object(key, file_buffer)

        if result.status / 100 != 2:
            return 1, None

        if private:
            bucket.put_object_acl(key, oss2.BUCKET_ACL_PRIVATE)
            url = self.get_sign_key(key)
        else:
            bucket.put_object_acl(key, oss2.BUCKET_ACL_PUBLIC_READ)
            url = 'https://%s.%s/%s' % (self.BUCKET, self.END_POINT, key)

        return 0, url


    def upload_file_from_path(self, file_path, key, bucket: Bucket, private=False):
        """
        上传文件
        :param file_path: file path
        :param key:
        :param bucket:
        :param private: 设置为私有(如果bucket拥有公共读权限，上传的文件会不能获取sign_url)
        :return err_code:
            0: 操作成功
            1: 操作失败
        """
        result = bucket.put_object_from_file(key, file_path)

        if result.status / 100 != 2:
            return 1, None

        if private:
            bucket.put_object_acl(key, oss2.BUCKET_ACL_PRIVATE)
            url = self.get_sign_key(key)
        else:
            bucket.put_object_acl(key, oss2.BUCKET_ACL_PUBLIC_READ)
            url = 'https://%s.%s/%s' % (self.BUCKET, self.END_POINT, key)

        return 0, url

    def get_sign_key(self, key, expires=60 * 30, use_internal_end_point=False):
        """
        获取签名url
        :param key:
        :param expires: 过期时间(单位：秒)
        :param use_internal_end_point:
        :return err_code:
            0: 操作成功
            1: 操作失败
        :return sign_key:
        """
        end_point = self.END_POINT
        if use_internal_end_point:
            end_point = self.END_INTERNAL_POINT
        bucket = self.get_oss_bucket()
        sign_url = bucket.sign_url('GET', key, expires)

        parsed_tuple = parse.urlparse(sign_url)
        data = {
            'scheme': parsed_tuple.scheme,
            'netloc': parsed_tuple.netloc,
            'path': parse.unquote(parsed_tuple.path),
            'params': parsed_tuple.params,
            'query': parsed_tuple.query,
            'fragment': parsed_tuple.fragment
        }
        unquoted_tuple = parse.ParseResult(**data)
        sign_url = parse.urlunparse(unquoted_tuple)

        return sign_url

    def get_file(self, key):
        """
        获取文件内容
        :param key:
        :return f: file object
        """
        bucket = self.get_oss_bucket()
        f = bucket.get_object(key)
        return f

    def gen_upload_sign_url(self, key, expire=60 * 30):
        """"""
        bucket = self.get_oss_bucket()
        sign_url = bucket.sign_url('PUT', key, expires=expire, headers={
            'Content-Type': 'application/octet-stream'
        })

        parsed_tuple = parse.urlparse(sign_url)
        data = {
            'scheme': parsed_tuple.scheme,
            'netloc': parsed_tuple.netloc,
            'path': parse.unquote(parsed_tuple.path),
            'params': parsed_tuple.params,
            'query': parsed_tuple.query,
            'fragment': parsed_tuple.fragment
        }
        unquoted_tuple = parse.ParseResult(**data)
        sign_url = parse.urlunparse(unquoted_tuple)
        return sign_url

    def get_oss_obj_to_file(bucket: Bucket, oss_path, file_path):
        """
        下载文件到本地
        @param bucket: oss桶
        @param oss_path: oss路径
        @param file_path: 本地文件路径
        """
        dir_path = os.path.dirname(file_path)
        if os.path.exists(dir_path):
            # 删除文件夹防止录入旧文件
            shutil.rmtree(dir_path)
        os.makedirs(dir_path)

        bucket.get_object_to_file(oss_path, file_path)

    def get_dir_to_file(bucket: Bucket, oss_path, dir_path):
        """
        下载文件夹到本地
        @param bucket: oss桶
        @param oss_path: oss路径
        @param dir_path: 本地目录
        """
        if os.path.exists(dir_path):
            # 删除文件夹防止录入旧文件
            shutil.rmtree(dir_path)
        os.makedirs(dir_path)

        for b in bucket.list_objects(oss_path).object_list:
            key = b.key
            if not key.endswith('/'):
                bucket.get_object_to_file(key, os.path.join(dir_path, key.split('/')[-1]))


oss_client = OssClient()